using System.ComponentModel;
using System.Reflection;
using System.Diagnostics;
using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using UnityEngine;
using UnityEditor;

using Vector2 = UnityEngine.Vector2;
using Debug = UnityEngine.Debug;
using Object = UnityEngine.Object;

namespace MeEditorFramework
{
    public class MeEditorWindow : EditorWindow
    {
        [MenuItem("MeEditor/UITool")]
        static void OpenGUILayoutExample(){
            MeEditorWindow window = (MeEditorWindow)EditorWindow
			.GetWindow(typeof(MeEditorWindow), false, "UI常用工具整合", true);
		    window.Show();
        }
        enum PageId{
            search,
            openwidonw,
            learnUnity
        }
        enum IMGUIMode{
            GUILayout,
            GUI
        }
        private PageId mCurPageId;
        private IMGUIMode mIMGUIMode;
        private GUILayoutAPI mGUILayoutAPI = new GUILayoutAPI();
        private GUIAPI mGUIAPI = new GUIAPI();
        private void OnGUI(){
            mCurPageId = (PageId)GUILayout.Toolbar((int)mCurPageId,Enum.GetNames(typeof(PageId)));
            if(mCurPageId == PageId.search){
                searchInit();
            }else if(mCurPageId == PageId.openwidonw){
                openwindowInit();
            }else if(mCurPageId == PageId.learnUnity){
                openwindowInit();
            }
        }
        #region openwindow
            IEnumerable<Type> mEditorWindowTypes;
            private void openwindowInit(){
                
                var editorWindowType = typeof(EditorWindow);
                var m_Parent = editorWindowType.GetField("m_Parent",BindingFlags.Instance|BindingFlags.NonPublic);
                mEditorWindowTypes = AppDomain.CurrentDomain.GetAssemblies()//获取到程序集
                    .SelectMany(assembly=> assembly.GetTypes())
                    .Where(type => type.IsSubclassOf(editorWindowType));
                
                foreach(var winowType in mEditorWindowTypes){
                    
                    EditorGUILayout.BeginHorizontal();
                    {
                        GUILayout.Label(winowType.Name);
                        if( GUILayout.Button("open",GUILayout.Width(80))){
                            GetWindow(editorWindowType).Show();
                        }
                    }
                    EditorGUILayout.EndHorizontal();
                  

                }
            }
        #endregion
        #region openwindow
            private void openLearnUity(){
               
                // 选择不同模式
                mIMGUIMode = (IMGUIMode)GUILayout.Toolbar((int)mIMGUIMode,Enum.GetNames(typeof(IMGUIMode)));
                if(mIMGUIMode == IMGUIMode.GUILayout){
                     mGUILayoutAPI.Draw();
                }else if(mIMGUIMode == IMGUIMode.GUI){
                    mGUIAPI.Draw();
                }
            }
        #endregion
        #region search
        private static Object findObj;
        private static Object newObj;

        private List<Object> result = new List<Object>();
        private Vector2 scrollPos = new Vector2();
        private bool checkPrefab = true;
        private bool checkScene = true;
        private bool checkMaterial = true;
        private string filter = "";
        private string oldfilter = "";
        private string[] guids;
        private bool isfirst = true;
        private List<string> prefabpathlist = new List<string>();
        private static string searchStr = "";
        private int len = 0;
        /// <summary>
        ///    查找图片预制件引用  根据文字搜索prefab
        /// </summary>
        private void searchInit() {

            EditorGUILayout.BeginVertical();
            // 资源排查情况
            // 1 直接转移文件到子common  实现复制资源到新目录
            // 3 整个prefab的替换 替换原来的prefab为新的通用prefab 注意：数据绑定要拷贝过来  文本绑定需要拷贝 情况比较复杂需要特别查看
            EditorGUILayout.BeginHorizontal();
            {
                EditorGUILayout.LabelField("UI常用控件整合");
               
            }
            EditorGUILayout.EndHorizontal();
            EditorGUILayout.Space();
            EditorGUILayout.BeginHorizontal();
            {
                EditorGUILayout.LabelField("查询图片",GUILayout.Width(60));
                findObj = EditorGUILayout.ObjectField(findObj, typeof(Object), true);
            }
            EditorGUILayout.EndHorizontal();
        
            EditorGUILayout.BeginHorizontal();
            {
                EditorGUILayout.LabelField("查询字符",GUILayout.Width(60));
                searchStr = EditorGUILayout.TextField(searchStr);
            }
            EditorGUILayout.EndHorizontal();
            EditorGUILayout.BeginHorizontal();
            {
                if (GUILayout.Button("查找引用",GUILayout.MinWidth(100),GUILayout.MinHeight(30))) {
                    result.Clear();
                    string assetGuid = "";
                    // 循环读取目录查找每个文件
                    Debug.Log("查找"+searchStr);
                    if (findObj == null) {
                        // 字符查询
                        if(searchStr == ""){
                        
                            return;
                        }
                        
                    }else{
                        string assetPath = AssetDatabase.GetAssetPath(findObj);
                        assetGuid = AssetDatabase.AssetPathToGUID(assetPath);
                    }
                    
                    
                    Stopwatch sw = new Stopwatch(); 
                    sw.Start(); 
                    filter = "";
                    if (checkPrefab) {
                        filter += "t:Prefab ";
                    }
                    if (checkScene) {
                    	filter += "t:Scene ";
                    }
                    if (checkMaterial) {
                    	filter += "t:Material ";
                    }
                    if(filter != oldfilter){
                        isfirst = true;
                    }
                    if(isfirst){
                        oldfilter = filter;
                        guids = AssetDatabase.FindAssets(filter, new[] { "Assets" });
                        prefabpathlist.Clear();
                        len = guids.Length;
                        Debug.Log("文件总数:"+len);
                        for (int i = 0; i < len; i++) {
                            string filePath = AssetDatabase.GUIDToAssetPath(guids[i]);
                            prefabpathlist.Add(filePath);
                        }
                        isfirst = false;
                    }
                    len = guids.Length;
                    Debug.Log("数量:"+len);
                    ArrayList filelist = new ArrayList();
                    //使用多线程提高查询效率
                    float findex = 1.0f;
                    string matchName = searchStr;
                    // 汉字进行unicode编码
                    if(!string.IsNullOrEmpty(searchStr)){
                        for (int i = 0; i < searchStr.Length; i++)
                        {
                            if ((int)searchStr[i] > 127)
                            {
                                matchName = matchName.Replace(searchStr[i].ToString(), String2Unicode(searchStr[i].ToString()));
                            }
                        }
                    }
                    Debug.Log("search>>" + matchName);
                    Parallel.ForEach(prefabpathlist, filePath =>
                    {
                        // 检查是否包含guid
                        findex = findex + 1;
                        try {
                            //Debug.Log("Finding..." + filePath);
                            // 某些文件读取会抛出异常
                            //测试数据流读取的时间 11s
                            using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read)) {
                                int nBytes = (int)fs.Length;//计算流的长度
                                byte[] byteArray = new byte[nBytes];//初始化用于MemoryStream的Buffer
                                int nBytesRead = fs.Read(byteArray, 0, nBytes);//将File里的内容一次性的全部读到byteArray中去
                                string str = System.Text.Encoding.Default.GetString ( byteArray );
                                bool ishave = false;
                                if(!string.IsNullOrEmpty(assetGuid)){
                                    if(str.Contains(assetGuid)){
                                        ishave = true;
                                    }
                                }
                                // 是否存在文本
                                if(!string.IsNullOrEmpty(searchStr)){
                                    if(str.Contains(matchName)){
                                        ishave = true;
                                    }
                                }
                                if(ishave){
                                    filelist.Add(filePath);
                                }

                            }
                            
                        } catch (System.Exception e) {
                            Debug.LogWarning(filePath + "\n" + e.ToString());
                        }
                    });
                    Debug.Log("foreach"+findex);
                    //EditorUtility.ClearProgressBar();
                    // 查找完毕添加显示
                    foreach (string i in filelist){
                        Object fileObject = AssetDatabase.LoadAssetAtPath(i, typeof(Object));
                        result.Add(fileObject);
                    }

                    
                    sw.Stop(); 
                    TimeSpan ts2 = sw.Elapsed; 

                    Debug.Log("查询总共花费s."+ts2.TotalMilliseconds/1000);
                }
            }
            EditorGUILayout.EndHorizontal();
            EditorGUILayout.Space();
            
            EditorGUILayout.LabelField("批量功能区");
                // 可以替换
            EditorGUILayout.BeginHorizontal();
            {
                EditorGUILayout.LabelField("替换图片",GUILayout.Width(60));
                newObj = EditorGUILayout.ObjectField(newObj, typeof(Object), true);
            }
            EditorGUILayout.EndHorizontal();
            EditorGUILayout.BeginHorizontal();
            {
                // 2 查询调用的prefab 更改图片资源为新的图片 实现替换功能
                if (GUILayout.Button("批量替换图片资源")) {
                    if (EditorUtility.DisplayDialog("提示", "确定要批量替换掉当前资源吗", "确定")){
                        if (findObj == null) {
                            EditorUtility.DisplayDialog("提示", "目标对象为空", "Ok");
                            return;
                        }
                        if (newObj == null) {
                            EditorUtility.DisplayDialog("提示", "替换新对象为空", "Ok");
                            return;
                        }
                        if(result.Count < 1){
                            EditorUtility.DisplayDialog("提示", "没有可替换引用组件", "Ok");
                            return;
                        }
                        string oldGuid = string.Empty;
                        string newGuid = string.Empty;
                        if (findObj)
                        {
                            oldGuid = findObj.GetType() == typeof(UnityEngine.Texture2D) || findObj.GetType() == typeof(UnityEngine.Sprite)
                            ? GetTexture2DAndSprideStr(findObj)
                            : AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(findObj));
                        }
                        if (newObj)
                        {
                            newGuid = newObj.GetType() == typeof(UnityEngine.Texture2D) || newObj.GetType() == typeof(UnityEngine.Sprite)
                            ? GetTexture2DAndSprideStr(newObj)
                            : AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(newObj));
                        }
                        Debug.Log("替换prefab图片资源");
                        //1 先搜索引用到的prefab 
                        //2 循环替换preab中 替换文件的guid
                        EditorApplication.update = delegate (){
                            for (int i = 0; i < result.Count; i++) {
                                Object destObj = result[i];
                                FindAssets(oldGuid,newGuid,destObj);
                                //EditorGUILayout.ObjectField(result[i], typeof(Object), true);
                            }
                        };
                        // 替换成功弹窗提示
                        EditorUtility.DisplayDialog("提示", "批量替换成功!", "Ok");
                    }
                }
            }
            EditorGUILayout.EndHorizontal();
            checkPrefab = EditorGUILayout.Toggle("Check Prefab : ", checkPrefab);

            checkScene = EditorGUILayout.Toggle("Check Scene : ", checkScene);
		    checkMaterial = EditorGUILayout.Toggle("Check Material : ", checkMaterial);
            string filterstr = "";
            if (checkPrefab) {
                filterstr += "Prefab ";
            }
            if (checkScene) {
                filterstr += "Scene ";
            }
            if (checkMaterial) {
                filterstr += "Material ";
            }
            EditorGUILayout.LabelField(filterstr + "Total: " + len);
            EditorGUILayout.LabelField("Result Count = " + result.Count);
            
            EditorGUILayout.Space();

            // 显示结果
            scrollPos = EditorGUILayout.BeginScrollView(scrollPos);
            {
                for (int i = 0; i < result.Count; i++) {
                    Object objfied = EditorGUILayout.ObjectField(result[i], typeof(Object), true);
                }
            }
            EditorGUILayout.EndScrollView();

            EditorGUILayout.EndVertical();
            
        }
        /// <summary>
        /// 取得替换资源内容 fileid guid
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        private static string GetTexture2DAndSprideStr(Object obj)
        {
            string path = AssetDatabase.GetAssetPath(obj);
            string guid = AssetDatabase.AssetPathToGUID(path);
            string fileID = string.Empty;
            if (obj.GetType() == typeof(UnityEngine.Texture2D)) fileID = "21300000";
            else if (obj.GetType() == typeof(UnityEngine.Sprite))
            {
                if (AssetDatabase.LoadAllAssetsAtPath(path).Length <= 2) fileID = "21300000";
                else
                {
                    string fileName = obj.name;
                    string matchName = fileName;
                    bool isHaveChinese = false;
                    for (int i = 0; i < fileName.Length; i++)
                    {
                        if ((int)fileName[i] > 127)
                        {
                            if (!isHaveChinese) isHaveChinese = true;
                            matchName = matchName.Replace(fileName[i].ToString(), String2Unicode(fileName[i].ToString()));
                        }
                    }
                    string metaPath = path + ".meta";
                    string[] metaTxt = File.ReadAllLines(metaPath);
                    if (isHaveChinese) matchName = "\"" + matchName + "\"";
                    string matchContent = string.Format(": {0}", matchName);
                    for (int i = 0; i < metaTxt.Length; i++)
                    {
                        if (metaTxt[i].Contains(matchContent))
                        {
                            #if UNITY_2019
                                fileID = metaTxt[i-1].Split(':')[1].Trim();
                            #else
                                fileID = metaTxt[i].Split(':')[0].Trim();
                            #endif
                            break;
                        }
                    }
                }
            }
            else return null;
            return string.IsNullOrEmpty(fileID) ? string.Empty : string.Format("fileID: {0}, guid: {1}", fileID, guid);
        }
        /// <summary>
        /// 判断字符串中是否包含中文
        /// </summary>
        /// <param name="str">需要判断的字符串</param>
        /// <returns>判断结果</returns>
        public static bool HasChinese(string str)
        {
            return Regex.IsMatch(str, @"[\u4e00-\u9fa5]");
        }
        private static void FindAssets(string oldGuid,string newGuid,Object destObj)
        {
            UnityEngine.Debug.LogWarning("oldGuid--->" + oldGuid);
            UnityEngine.Debug.LogWarning("newGuid--->" + newGuid);
            string assetPath = AssetDatabase.GetAssetPath(destObj);
            //string file = System.IO.Directory.GetFiles(assetPath);
            string objTxt = File.ReadAllText(assetPath);
            if (Regex.IsMatch(objTxt, oldGuid))
            {
                objTxt = objTxt.Replace(oldGuid, newGuid);
                File.WriteAllText(assetPath, objTxt);
                Debug.Log(assetPath, AssetDatabase.LoadAssetAtPath<Object>(assetPath.Replace(Application.dataPath, "Assets")));
            }
        }
        /// <summary>
        /// 字符串转Unicode
        /// </summary>
        /// <param name="source">源字符串</param>
        /// <returns>Unicode编码后的字符串</returns>
        public static string String2Unicode(string source)
        {
            byte[] bytes = Encoding.Unicode.GetBytes(source);
            StringBuilder stringBuilder = new StringBuilder();
            for (int i = 0; i < bytes.Length; i += 2)
            {
                stringBuilder.AppendFormat("\\u{0}{1}", bytes[i + 1].ToString("x").PadLeft(2, '0').ToUpper(), bytes[i].ToString("x").PadLeft(2, '0').ToUpper());
            }

            return stringBuilder.ToString();
        }

        /// <summary>
        /// Unicode转字符串
        /// </summary>
        /// <param name="source">经过Unicode编码的字符串</param>
        /// <returns>正常字符串</returns>
        public static string Unicode2String(string source)
        {
            return new Regex(@"\\u([0-9A-F]{4})", RegexOptions.IgnoreCase | RegexOptions.Compiled).Replace(
                        source, x => string.Empty + System.Convert.ToChar(System.Convert.ToUInt16(x.Result("$1"), 16)));
        }
        #endregion


    }


}
